package com.trgis.yhmap.util.wmtsproxy.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;


/**
 * 限制访问次数的策略，如5分钟内单个用户调用上限30000
 * @author wangfy
 */
public class IPFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(IPFilter.class);

    @Autowired
    private AccessRuler ruler;

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;

        String ip = getIpAddr(request);

        if (ruler.isInIPHMD(ip)) {
            resp.setContentType("text/html");
            ((HttpServletResponse) resp).setStatus(403);
            byte[] contentBytes = ruler.hmdInfo.getBytes(StandardCharsets.UTF_8);
            resp.setContentLength(contentBytes.length);
            resp.getOutputStream().write(contentBytes);
            resp.getOutputStream().flush();
            return;
        }

        String referer = request.getHeader("referer");
        if (null == referer) {
            referer = "";
        }
        if(!referer.isEmpty()){
            referer = referer.replace("http://", "").replace("https://", "")
                    .replaceAll("(:\\d+)?/\\S*", "");
        }

        // 如果IP或referer在白名单内，正常放行
        if (ruler.isInIPBMD(ip) || ruler.isInRefererBMD(referer)) {
            chain.doFilter(req, resp);
            return;
        }

        if (!isRequestGetTile(request)) {
            chain.doFilter(req, resp);
            return;
        }

        ResponseWrapper wrapperResponse = new ResponseWrapper((HttpServletResponse) resp);
        if (checkIPAndReferer(ip, referer)){
            if (!ruler.enable_404_png){
                chain.doFilter(req, resp);
                return;
            }

            chain.doFilter(req, wrapperResponse);

            // 查看请求返回内容，没有瓦片的用包含提示信息的图片替换
            int respStatus = ((HttpServletResponse) resp).getStatus();

            ServletOutputStream out = resp.getOutputStream();
            byte[] contentBytes;
            // 把超出范围的瓦片替换成提示图片
            if (404 == respStatus) {
//                log.info("IP：{} 的请求不存在，返回404图片 header referer 为 {}", ip, referer);
                resp.setContentType("image/png");
                ((HttpServletResponse) resp).setStatus(200);
                contentBytes = ruler.getPngBytes();
            } else {
//                log.info("IP: {} referer 为 {}", ip, referer);
                contentBytes = wrapperResponse.getContent();
            }
            resp.setContentLength(contentBytes.length);
            out.write(contentBytes);
            out.flush();
        } else {
            log.info("根据限流规则临时中断 {} 的访问", ip);
            resp.setContentType("text/html");
            ((HttpServletResponse) resp).setStatus(403);
            byte[] contentBytes = ruler.getRulerInfo().getBytes(StandardCharsets.UTF_8);
            resp.setContentLength(contentBytes.length);
            resp.getOutputStream().write(contentBytes);
            resp.getOutputStream().flush();
        }
    }

    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ipIsNull(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
            if(ipIsNull(ip)){
                ip = request.getHeader("WL-Proxy-Client-IP");
                if(ipIsNull(ip)){
                    ip = request.getHeader("X-Real-IP");
                    if (ipIsNull(ip)) {
                        ip = request.getRemoteAddr();
                    }
                }
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        return ip;
    }

    private boolean ipIsNull(String ip){
        return null == ip || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "127.0.0.1".equalsIgnoreCase(ip);
    }

    private boolean checkIPAndReferer(String ip, String referer){
        if (ipIsNull(ip)) {
            return true;
        }
        return ruler.checkIPAndReferer(ip, referer);
    }

    private boolean isRequestGetTile(HttpServletRequest request) {
        for (Enumeration<String> params = request.getParameterNames(); params.hasMoreElements(); ) {
            String req = params.nextElement();
            if ("request".equalsIgnoreCase(req)) {
                if ("GetTile".equalsIgnoreCase(request.getParameter(req))) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }
}
